package morpion;

import java.util.LinkedList;

public class Reseau {
	LinkedList<Sommet> initial;
	LinkedList<Sommet>	cache;
	LinkedList<Sommet> fin;

	public Reseau(int nb_initial, int nb_cache){
		int nom_sommet=0;

		// Creation des sommets
		initial=new LinkedList<Sommet>();
		cache=new LinkedList<Sommet>();
		fin=new LinkedList<Sommet>();
		for(int i=0; i<nb_initial; i++)
			initial.add(new Sommet(0,nom_sommet++));
		for(int i=0; i<nb_cache; i++)
			cache.add(new Sommet(0,nom_sommet++));
		for(int i=0; i<Morpion.ROW*Morpion.COL; i++)		// Changer la classe Morpion en othello
			fin.add(new Sommet(0
					,nom_sommet++));		

		//creation des arretes
		LinkedList<Arete> temp=new LinkedList<Arete>();
		int sommet_entrant,sommet_sortant;
		int nom=0;
		for(int j=0;j<nb_initial;j++)
		{
			sommet_entrant=j;
			temp.clear();
			for(int i=0;i<nb_cache;i++)
			{
				sommet_sortant=i;
				Arete arete=new Arete(nom++,initial.get(sommet_entrant),cache.get(sommet_sortant),1);
				temp.add(arete);
				cache.get(sommet_sortant).entrant.add(arete);
			}
			initial.get(j).sortant=(LinkedList<Arete>) temp.clone();
			initial.get(j).entrant=null;
		}
		for(int i=0;i<nb_cache;i++)
		{
			sommet_entrant=i;
			temp.clear();
			for(int j=0;j<Morpion.COL*Morpion.ROW;j++)
			{
				sommet_sortant=j;
				Arete arete=new Arete(nom++,cache.get(sommet_entrant),fin.get(sommet_sortant),1);
				temp.add(arete);
				fin.get(j).entrant.add(arete);
				fin.get(j).sortant=null;
			}
			cache.get(i).sortant=(LinkedList<Arete>) temp.clone();
		}
	}

	public void Affiche_reseau()
	{
		for(Sommet init:initial)
		{
			System.out.print(" ["+init.nom+"-"+init.valeur+"] ");
			for(Arete a:init.sortant)
			{
				System.out.print("("+a.nom+")"+a.poids+" ");
			}
			System.out.println();
		}
		for(Sommet cach:cache)
		{
			for(Arete a:cach.entrant)
			{
				System.out.print("("+a.nom+")"+a.poids+" ");
			}
			System.out.print("  ["+cach.nom+"-"+cach.valeur+"]  ");
			for(Arete a:cach.sortant)
			{
				System.out.print("("+a.nom+")"+a.poids+" ");
			}
			System.out.println();
		}
		for(Sommet end:fin)
		{
			for(Arete a:end.entrant)
			{
				System.out.print("("+a.nom+")"+a.poids+" ");
			}
			System.out.println("  ["+end.nom+"-"+end.valeur+"]  ");
		}
	}


	/**
	 * La fonction met un poids sur l'arete situe entre le sommet de nom1 et le sommet de nom2
	 * @param nom1 nom du sommet entrant de l'arete, -1 si on ne considere pas le sommet
	 * @param nom2 nom du sommet entrant ou sortant de l'arete, -1 si on ne considere pas le sommet
	 * @param nom3 nom du sommet sortant de l'arete, -1 si on ne considere pas le sommet
	 * @poids poids que l'on va mettre sur l'arete
	 * @return Renvoie 0 si tout c'est bien passe, -1 sinon
	 */
	int mettre_poids_arete(int nom1,int nom2,int nom3, double poids)
	{
		if(nom2==-1) return-1;
		else if(nom1==-1)
		{
			try
			{
				Sommet entrant=cache.get(nom2-initial.size());
				try
				{
					Sommet sortant=fin.get(nom3-(initial.size()+cache.size()));
					Arete a=entrant.sortant.get(sortant.nom-(initial.size()+cache.size()));
					a.poids=poids;
					System.out.println("Arete numero "+a.nom);
				}
				catch(IndexOutOfBoundsException y)
				{
					return -1;
				}
			}
			catch(IndexOutOfBoundsException y)
			{
				return -1;
			}

		}
		else if(nom3==-1)
		{
			try
			{
				Sommet entrant=initial.get(nom1);
				try
				{
					Sommet sortant=cache.get(nom2-initial.size());
					Arete a=entrant.sortant.get(sortant.nom-initial.size());
					a.poids=poids;
					System.out.println("Arete numero "+a.nom);
				}
				catch(IndexOutOfBoundsException y)
				{
					return -1;
				}
			}
			catch(IndexOutOfBoundsException y)
			{
				return -1;
			}
		}
		else return -1;

		return 0;
	}

	/**
	 * Mets le poids sur le sommet de nom "nom"
	 * @param nom nom du smmet
	 * @param poids poids que l'on veut mettre sur le sommet
	 * @return 0 si tout va bien, -1 sinon
	 */
	int mettre_poids_sommet(int nom,double poids)
	{
		if(nom<initial.size())
		{
			Sommet s=initial.get(nom);
			s.valeur=poids;
		}
		else if(nom<(initial.size()+cache.size()))
		{
			Sommet s=cache.get(nom-initial.size());
			s.valeur=poids;
		}
		else if(nom<(initial.size()+cache.size()+fin.size()))
		{
			Sommet s=cache.get(nom-(initial.size()+cache.size()));
			s.valeur=poids;
		}
		else return -1;

		return 0;
	}

	/**
	 * Cacule la valeur d'un sommet s situer sur la liste de fin
	 * @param s sommet dont on veut caculer le poids
	 * @return la valeur trouvee
	 */
	int cacul_valeur(Sommet s)
	{
		return 0;
	}


	//TODO finir
	public void learn(LinkedList<Coup> l_coup, double gain)
	{
		double erreur;
		double deltaK;
		double[] deltaJ;
		double aK;

		for(int i = 0; i < l_coup.size(); i++)
		{
			aK = l_coup.get(i).getEstimationScore();
			gain = Coup.calcGain(gain, aK, i);
			erreur = aK - gain;
			deltaK = aK * (1 - aK) * (gain - aK);
			deltaJ = new double[fin.get(l_coup.get(i).getCoup()).entrant.size()];

			for(int j = 0; j < fin.get(l_coup.get(i).getCoup()).entrant.size(); j++)
			{
				//deltaJ[j] = aJ(1 - aJ) + deltaK * wKj
				deltaJ[j] = l_coup.get(i).getPoid_cache()[j] 
				                                          * (1 - l_coup.get(i).getPoid_cache()[j]) 
				                                          + deltaK * Arete.find(fin.get(l_coup.get(i).getCoup()).entrant, 
				                                        		  cache.get(j).nom, 
				                                        		  fin.get(l_coup.get(i).getCoup()).nom).poids;	

				Arete.find(fin.get(l_coup.get(i).getCoup()).entrant, cache.get(j).nom, fin.get(l_coup.get(i).getCoup()).nom).poids 
				-= -1 * Param.nappa * deltaK * l_coup.get(i).getPoid_cache()[j];
			}

			for(int j = 0; j < cache.size(); j++)
			{
				for(int k = 0; k < cache.get(j).entrant.size(); k++)
				{
					Arete.find(cache.get(j).entrant, initial.get(k).nom, cache.get(j).nom).poids
					-= -1 * Param.nappa * deltaJ[j] * l_coup.get(i).getPoid_initial()[k];
				}
			} //finish ?

			/*
			 *  Ai -------------Wij----------- Aj
			 *  DWij = -nappa * deltaJ * Ai
			 *  Wji = Wji + DWij
			 * 
			 */

		}

	}

}
